using OpenTK;

namespace ColladaDotNet.OpenTKMapping
{
	public class Sampler : DocumentLibraryElement<sampler>
	{
		internal override void Load(sampler colladaData)
		{
			base.Load(colladaData);
			foreach (var inputLocal in colladaData.input)
			{
				switch (inputLocal.semantic)
				{
					case "INPUT":
						inputSource = Document.GetElementByUrl<Source>(inputLocal.source);
						break;
					case "OUTPUT":
						outputSource = Document.GetElementByUrl<Source>(inputLocal.source);
						break;
					case "INTERPOLATION":
						interpolationSource = Document.GetElementByUrl<Source>(inputLocal.source);
						break;
				}
			}
		}

		private Source inputSource;
		private Source outputSource;
		private Source interpolationSource;

		public void Apply(object target, double time)
		{
			if (inputSource == null)
				return;
			var paramTime = InputTime;
			var paramTransform = outputSource["TRANSFORM"];
			var paramInterpolation = interpolationSource["INTERPOLATION"];

			ulong i = 0;
			for (i = 0; i < paramTime.Count; ++i)
			{
				if (time <= paramTime.GetDouble(i))
					break;
			}
			ulong j;
			double k = 1;
			if (i == 0)
			{
				j = paramTime.Count - 1;
				k = 0;
			}
			else if (i >= paramTime.Count)
			{
				j = paramTime.Count-1;
				i = 0;
				k = 1;
			}
			else
			{
				i = i - 1;
				j = i+1;
				k = (time - paramTime.GetDouble(i)) / (paramTime.GetDouble(j) - paramTime.GetDouble(i));
			}

			if (target is Matrix)
			{
				if (paramTransform.ParamType == typeof(Matrix4d))
				{
					SampleMatrix4dToMatrix(paramTransform.GetMatrix(i), paramTransform.GetMatrix(j),k,(Matrix)target);
					return;
				}
			}
		}

		private void SampleMatrix4dToMatrix(Matrix4d m1, Matrix4d m2, double k, Matrix target)
		{
			Matrix4d m = m1;
			m.M11 = m.M11 * (1 - k) + m2.M11 * k;
			m.M12 = m.M12 * (1 - k) + m2.M12 * k;
			m.M13 = m.M13 * (1 - k) + m2.M13 * k;
			m.M14 = m.M14 * (1 - k) + m2.M14 * k;
			m.M21 = m.M21 * (1 - k) + m2.M21 * k;
			m.M22 = m.M22 * (1 - k) + m2.M22 * k;
			m.M23 = m.M23 * (1 - k) + m2.M23 * k;
			m.M24 = m.M24 * (1 - k) + m2.M24 * k;

			m.M31 = m.M31 * (1 - k) + m2.M31 * k;
			m.M32 = m.M32 * (1 - k) + m2.M32 * k;
			m.M33 = m.M33 * (1 - k) + m2.M33 * k;
			m.M34 = m.M34 * (1 - k) + m2.M34 * k;

			m.M41 = m.M41 * (1 - k) + m2.M41 * k;
			m.M42 = m.M42 * (1 - k) + m2.M42 * k;
			m.M43 = m.M43 * (1 - k) + m2.M43 * k;
			m.M44 = m.M44 * (1 - k) + m2.M44 * k;
			target.Value4d = m;
		}
		public SourceParam InputTime
		{
			get
			{
				return inputSource["TIME"];
			}
		}

		public Source Input
		{
			get
			{
				return inputSource;
			}
		}
	}
}